package service

import (
	"awesomeProject/app/model"
	"awesomeProject/app/request"
	"awesomeProject/app/response"
	"awesomeProject/global"
	"awesomeProject/util"
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"strconv"
	"strings"
	"time"
)

type OrderSrv struct{}

func (r *OrderSrv) Pagination(req request.OrderPagination, shopIds []uint, operator model.User) response.Resp {
	filter := bson.D{}
	//global.LoggerOut(req.ShopId)
	//global.LoggerOut(shopIds)
	//global.LoggerOut(req.CompanyId)
	if req.ShopId != 0 {
		filter = append(filter, bson.E{Key: "shop_id", Value: req.ShopId})
	} else {
		if req.CompanyId != 0 && operator.SuperAdmin {
			var accounts []model.Account
			//err := global.Gorm.Where("company_id=? and status=1", req.CompanyId).Find(&accounts).Error
			//禁用的店铺里的数据，也展示出来
			err := global.Gorm.Where("company_id=?", req.CompanyId).Find(&accounts).Error
			if err != nil {
				return response.ErrQuery
			}
			shopIds = []uint{}
			for _, account := range accounts {
				shopIds = append(shopIds, account.ShopId)
			}
		}
		if len(shopIds) > 0 {
			filter = append(filter, bson.E{Key: "shop_id", Value: bson.M{"$in": shopIds}})
		}
	}
	if req.OrderSn != "" {
		filter = append(filter, bson.E{Key: "orderSn", Value: req.OrderSn})
	}
	if req.DeliverPlaceCode != "" {
		filter = append(filter, bson.E{Key: "deliverPlace", Value: req.DeliverPlaceCode})
	}
	if req.Status != 0 {
		filter = append(filter, bson.E{Key: "status", Value: req.Status})
	}
	if req.PlacedOrderAtS != "" {
		PlacedOrderAtS, _ := time.ParseInLocation("2006-01-02", req.PlacedOrderAtS, time.Local)
		filter = append(filter, bson.E{Key: "placedOrderAt", Value: bson.M{"$gte": PlacedOrderAtS.Unix() * 1000}})
	}
	if req.PlacedOrderAtE != "" {
		placedOrderAtE, _ := time.ParseInLocation("2006-01-02", req.PlacedOrderAtE, time.Local)
		placedOrderAtE = placedOrderAtE.AddDate(0, 0, 1)
		filter = append(filter, bson.E{Key: "placedOrderAt", Value: bson.M{"$lt": placedOrderAtE.Unix() * 1000}})
	}
	if req.ReadiedAtS != "" {
		ReadiedAtS, _ := time.ParseInLocation("2006-01-02", req.ReadiedAtS, time.Local)
		filter = append(filter, bson.E{Key: "readiedAt", Value: bson.M{"$gte": ReadiedAtS.Unix() * 1000}})
	}
	if req.ReadiedAtE != "" {
		readiedAtE, _ := time.ParseInLocation("2006-01-02", req.PlacedOrderAtE, time.Local)
		readiedAtE = readiedAtE.AddDate(0, 0, 1)
		filter = append(filter, bson.E{Key: "readiedAt", Value: bson.M{"$lt": readiedAtE.Unix() * 1000}})
	}

	if req.SkuTypeValue != "" {
		if req.SkuType == "skuId" {
			skuId, _ := strconv.Atoi(req.SkuTypeValue)
			filter = append(filter, bson.E{Key: "skus.skuId", Value: skuId})
		} else if req.SkuType == "skuNo" {
			filter = append(filter, bson.E{Key: "skus.skuNo", Value: req.SkuTypeValue})
		} else if req.SkuType == "itemId" {
			itemId, _ := strconv.Atoi(req.SkuTypeValue)
			filter = append(filter, bson.E{Key: "skus.itemId", Value: itemId})
		} else if req.SkuType == "itemNo" {
			filter = append(filter, bson.E{Key: "skus.itemNo", Value: req.SkuTypeValue})
		}
	}
	if req.OverTime != 0 {
		filter = append(filter, bson.E{Key: "skus.overTime", Value: req.OverTime})
	}
	if req.CancelMark != -1 {
		filter = append(filter, bson.E{Key: "skus.cancelMark", Value: req.CancelMark})
	}
	if req.OverTimeMark != -1 {
		filter = append(filter, bson.E{Key: "skus.overTimeMark", Value: req.OverTimeMark})
	}
	if req.CountDown > 0 {
		currentTime := time.Now().Unix() + int64(req.CountDown*3600) - 5*24*3600
		filter = append(filter, bson.E{Key: "paymentAt", Value: bson.M{"$lte": currentTime * 1000}})
		hasStatusFilter := false
		filterStatus := []uint{8, 9, 10}
		for _, e := range filter {
			if e.Key == "status" {
				hasStatusFilter = true
				if !util.Contains(filterStatus, uint(req.Status)) {
					filter = append(filter, bson.E{Key: "status", Value: 0})
				}
			}
		}
		if !hasStatusFilter {
			filter = append(filter, bson.E{Key: "status", Value: bson.M{"$in": filterStatus}})
		}
	}
	if req.Title != "" {
		filter = append(filter, bson.E{Key: "skus.itemTitle", Value: bson.M{"$regex": primitive.Regex{Pattern: ".*"+strings.Trim(req.Title, " ")+".*", Options: "i"}}})
	}
	offset := (req.PageIndex - 1) * req.PageSize
	match := bson.D{{"$match", filter}}
	sort := bson.D{{"$sort", bson.M{"placedOrderAt": -1}}}
	skip := bson.D{{"$skip", offset}}
	limit := bson.D{{"$limit", req.PageSize}}
	cursor, err := global.MongoDB.Collection("orders").Aggregate(context.TODO(), mongo.Pipeline{match, sort, skip, limit})
	if err != nil {
		return response.ErrQuery.SetMsg(err.Error())
	}
	var orders []model.Order
	if err = cursor.All(context.TODO(), &orders); err != nil {
		return response.ErrQuery.SetMsg(err.Error())
	}
	if len(orders) == 0 {
		return response.OK.WithData(map[string]interface{}{
			"total": 0,
			"list":  orders,
		})
	}

	count := bson.D{{"$count", "total"}}
	countCursor, err := global.MongoDB.Collection("orders").Aggregate(context.TODO(), mongo.Pipeline{match, count})
	if err != nil {
		return response.ErrQuery.SetMsg(err.Error())
	}
	var countResult []map[string]interface{}
	if err = countCursor.All(context.TODO(), &countResult); err != nil {
		return response.ErrQuery.SetMsg(err.Error())
	}

	var ordersExtra []model.OrderWithExtra
	if len(orders) > 0 {
		for _, order := range orders {
			orderExtra := model.OrderWithExtra{}
			util.StructAssign(&orderExtra, &order)

			for _, sku := range *orderExtra.Skus {
				//fmt.Println(orderExtra.ShopId)
				//fmt.Println(sku.ItemId)
				where := bson.D{
					{"shopId", orderExtra.ShopId},
					{"itemId", sku.ItemId},
				}
				var overmerchant model.OrderMerchantList
				err2 := global.MongoDB.Collection("merchant_list").FindOne(context.TODO(), where).Decode(&overmerchant)
				if err2 == nil {
					orderExtra.PreCreatedAtString = overmerchant.PreCreatedAtString
					break
				}
			}

			// ------ 订单进度 begin -------
			//global.LoggerOut(orderExtra.OrderSn)
			var orderOrdersProcess *model.OrderOrderProcess
			orderOrderProcess := model.OrderOrderProcess{}

			//filter := bson.D{{"orderSn", orderExtra.OrderSn}}
			//filter := bson.D{bson.E{Key: "orderSn", Value: orderExtra.OrderSn}}

			filter := bson.D{}
			filter = append(filter, bson.E{Key: "orderSn", Value: orderExtra.OrderSn})
			match := bson.D{{"$match", filter}}
			sort := bson.D{{"$sort", bson.M{"processDate": -1, "id": -1, "sort": 1}}}
			skip := bson.D{{"$skip", 0}}
			limit := bson.D{{"$limit", 1}}

			var orderProcess []model.OrderProcess
			cursor, err := global.MongoDB.Collection(model.OrderProcess{}.TableName()).Aggregate(context.TODO(), mongo.Pipeline{match, sort, skip, limit})
			if err = cursor.All(context.TODO(), &orderProcess); err != nil {
				return response.ErrQuery.SetMsg(err.Error())
			}
			if len(orderProcess) > 0 {
				for _, op := range orderProcess {
					//global.LoggerOut(op.UpdateAt)
					//global.LoggerOut(op.ProcessDate)
					var updateAtOverTime string  // 未跟踪提示
					//if op.UpdateAt.IsZero() {
					//	updateAtOverTime = "未跟踪"
					//} else {
					//	if op.UpdateAt.Add(time.Duration(3) * 24 * time.Hour).Before(time.Now().UTC()) {
					//		updateAtOverTime = "超过3天未跟踪"
					//	} else if op.UpdateAt.Add(time.Duration(1) * 24 * time.Hour).Before(time.Now().UTC()) {
					//		updateAtOverTime = "超过24H未跟踪"
					//	}
					//}

					if op.ProcessDate == "" {
						updateAtOverTime = "未跟踪"
					} else {
						layout := "2006-01-02 15:04:05"
						ProcessAt, _ := time.Parse(layout, op.ProcessDate + " 23:59:59")
						if ProcessAt.Add(time.Duration(3) * 24 * time.Hour).Before(time.Now()) {
							updateAtOverTime = "超过3天未跟踪"
						} else if ProcessAt.Add(time.Duration(1) * 24 * time.Hour).Before(time.Now()) {
							updateAtOverTime = "超过24H未跟踪"
						}
					}

					orderOrderProcess.LastUpdateUser = op.UpdateUser
					orderOrderProcess.LastUpdateAt = op.UpdateAt
					orderOrderProcess.LastProcessDate = op.ProcessDate
					orderOrderProcess.LastProcessContent = op.ProcessContent
					orderOrderProcess.UpdateAtOverTime = updateAtOverTime
					orderOrdersProcess = &orderOrderProcess
					break
				}
			}
			orderExtra.OrderOrderProcess = orderOrdersProcess
			// ------ 订单进度 end -------

			ordersExtra = append(ordersExtra, orderExtra)
		}
	}

	return response.OK.WithData(map[string]interface{}{
		"total": countResult[0]["total"],
		//"list":  orders,
		"list":  ordersExtra,
	})
}

func (r *OrderSrv) StatusCount(req request.OrderStatusCount, shopIds []uint, operator model.User) response.Resp {
	filter := bson.D{}
	if req.ShopId != 0 {
		filter = append(filter, bson.E{Key: "shop_id", Value: req.ShopId})
	} else {
		if req.CompanyId != 0 && operator.SuperAdmin {
			var accounts []model.Account
			//err := global.Gorm.Where("company_id=? and status=1", req.CompanyId).Find(&accounts).Error
			//禁用的店铺里的数据，也展示出来
			err := global.Gorm.Where("company_id=?", req.CompanyId).Find(&accounts).Error
			if err != nil {
				return response.ErrQuery
			}
			shopIds = []uint{}
			for _, account := range accounts {
				shopIds = append(shopIds, account.ShopId)
			}
		}
		if len(shopIds) > 0 {
			filter = append(filter, bson.E{Key: "shop_id", Value: bson.M{"$in": shopIds}})
		}
	}
	if req.OrderSn != "" {
		filter = append(filter, bson.E{Key: "orderSn", Value: req.OrderSn})
	}
	if req.DeliverPlaceCode != "" {
		filter = append(filter, bson.E{Key: "deliverPlace", Value: req.DeliverPlaceCode})
	}
	if req.PlacedOrderAtS != "" {
		PlacedOrderAtS, _ := time.ParseInLocation("2006-01-02", req.PlacedOrderAtS, time.Local)
		filter = append(filter, bson.E{Key: "placedOrderAt", Value: bson.M{"$gte": PlacedOrderAtS.Unix() * 1000}})
	}
	if req.PlacedOrderAtE != "" {
		placedOrderAtE, _ := time.ParseInLocation("2006-01-02", req.PlacedOrderAtE, time.Local)
		placedOrderAtE = placedOrderAtE.AddDate(0, 0, 1)
		filter = append(filter, bson.E{Key: "placedOrderAt", Value: bson.M{"$lt": placedOrderAtE.Unix() * 1000}})
	}
	if req.ReadiedAtS != "" {
		ReadiedAtS, _ := time.ParseInLocation("2006-01-02", req.ReadiedAtS, time.Local)
		filter = append(filter, bson.E{Key: "readiedAt", Value: bson.M{"$gte": ReadiedAtS.Unix() * 1000}})
	}
	if req.ReadiedAtE != "" {
		readiedAtE, _ := time.ParseInLocation("2006-01-02", req.PlacedOrderAtE, time.Local)
		readiedAtE = readiedAtE.AddDate(0, 0, 1)
		filter = append(filter, bson.E{Key: "readiedAt", Value: bson.M{"$lt": readiedAtE.Unix() * 1000}})
	}

	if req.SkuTypeValue != "" {
		if req.SkuType == "skuId" {
			skuId, _ := strconv.Atoi(req.SkuTypeValue)
			filter = append(filter, bson.E{Key: "skus.skuId", Value: skuId})
		} else if req.SkuType == "skuNo" {
			filter = append(filter, bson.E{Key: "skus.skuNo", Value: req.SkuTypeValue})
		} else if req.SkuType == "itemId" {
			itemId, _ := strconv.Atoi(req.SkuTypeValue)
			filter = append(filter, bson.E{Key: "skus.itemId", Value: itemId})
		} else if req.SkuType == "itemNo" {
			filter = append(filter, bson.E{Key: "skus.itemNo", Value: req.SkuTypeValue})
		}
	}
	if req.OverTime != 0 {
		filter = append(filter, bson.E{Key: "skus.overTime", Value: req.OverTime})
	}
	if req.CancelMark != -1 {
		filter = append(filter, bson.E{Key: "skus.cancelMark", Value: req.CancelMark})
	}
	if req.OverTimeMark != -1 {
		filter = append(filter, bson.E{Key: "skus.overTimeMark", Value: req.OverTimeMark})
	}
	if req.CountDown > 0 {
		currentTime := time.Now().Unix() + int64(req.CountDown*3600) - 5*24*3600
		filter = append(filter, bson.E{Key: "paymentAt", Value: bson.M{"$lte": currentTime * 1000}})
		filterStatus := []int{8, 9, 10}
		filter = append(filter, bson.E{Key: "status", Value: bson.M{"$in": filterStatus}})
	}

	match := bson.D{{"$match", filter}}
	group := bson.D{{
		"$group", bson.D{
			{"_id", "$status"},
			{"count", bson.M{"$sum": 1}},
		},
	}}
	cursor, err := global.MongoDB.Collection("orders").Aggregate(context.TODO(), mongo.Pipeline{match, group})
	if err != nil {
		return response.ErrQuery.SetMsg(err.Error())
	}
	var result []model.OrderStatusCount
	if err = cursor.All(context.TODO(), &result); err != nil {
		return response.ErrQuery.SetMsg(err.Error())
	}

	resp := model.FOrderStatusCount{}
	resp.ShopId = req.ShopId
	resp.Status = req.Status
	for _, res := range result {
		resp.All += res.Count
		if res.ID == 3 {
			resp.Shipped += res.Count
		} else if res.ID == 5 {
			resp.Success += res.Count
		} else if res.ID == 7 || res.ID == 99 {
			resp.Closed += res.Count
			if res.ID == 7 {
				resp.Reject += res.Count
			} else if res.ID == 99 {
				resp.Canceled += res.Count
			}
		} else if res.ID == 8 || res.ID == 9 || res.ID == 10 {
			if res.ID == 8 {
				resp.BeReplenish += res.Count
			} else if res.ID == 9 {
				resp.Replenishing += res.Count
			} else if res.ID == 10 {
				resp.Handler += res.Count
			}
			resp.UnShipped += res.Count
		}
	}

	return response.OK.WithData(resp)
}

func (r *OrderSrv) Export(ctx *gin.Context, req request.OrderExport) error {
	filter := bson.D{}
	if req.ShopId != 0 {
		filter = append(filter, bson.E{Key: "shop_id", Value: req.ShopId})
	}
	if req.OrderSn != "" {
		filter = append(filter, bson.E{Key: "orderSn", Value: req.OrderSn})
	}
	if req.DeliverPlaceCode != "" {
		filter = append(filter, bson.E{Key: "deliverPlace", Value: req.DeliverPlaceCode})
	}
	if req.Status != 0 {
		filter = append(filter, bson.E{Key: "status", Value: req.Status})
	}
	if req.PlacedOrderAtS != "" {
		PlacedOrderAtS, _ := time.ParseInLocation("2006-01-02", req.PlacedOrderAtS, time.Local)
		filter = append(filter, bson.E{Key: "placedOrderAt", Value: bson.M{"$gte": PlacedOrderAtS.Unix() * 1000}})
	}
	if req.PlacedOrderAtE != "" {
		placedOrderAtE, _ := time.ParseInLocation("2006-01-02", req.PlacedOrderAtE, time.Local)
		placedOrderAtE = placedOrderAtE.AddDate(0, 0, 1)
		filter = append(filter, bson.E{Key: "placedOrderAt", Value: bson.M{"$lt": placedOrderAtE.Unix() * 1000}})
	}
	if req.ReadiedAtS != "" {
		ReadiedAtS, _ := time.ParseInLocation("2006-01-02", req.ReadiedAtS, time.Local)
		filter = append(filter, bson.E{Key: "readiedAt", Value: bson.M{"$gte": ReadiedAtS.Unix() * 1000}})
	}
	if req.ReadiedAtE != "" {
		readiedAtE, _ := time.ParseInLocation("2006-01-02", req.PlacedOrderAtE, time.Local)
		readiedAtE = readiedAtE.AddDate(0, 0, 1)
		filter = append(filter, bson.E{Key: "readiedAt", Value: bson.M{"$lt": readiedAtE.Unix() * 1000}})
	}

	if req.SkuTypeValue != "" {
		if req.SkuType == "skuId" {
			filter = append(filter, bson.E{Key: "skus.skuId", Value: req.SkuTypeValue})
		} else if req.SkuType == "skuNo" {
			filter = append(filter, bson.E{Key: "skus.skuNo", Value: req.SkuTypeValue})
		} else if req.SkuType == "itemId" {
			filter = append(filter, bson.E{Key: "skus.itemId", Value: req.SkuTypeValue})
		} else if req.SkuType == "itemNo" {
			filter = append(filter, bson.E{Key: "skus.itemNo", Value: req.SkuTypeValue})
		}
	}
	if req.OverTime != 0 {
		filter = append(filter, bson.E{Key: "skus.overTime", Value: req.OverTime})
	}
	if req.CancelMark != -1 {
		filter = append(filter, bson.E{Key: "skus.cancelMark", Value: req.CancelMark})
	}
	if req.OverTimeMark != -1 {
		filter = append(filter, bson.E{Key: "skus.overTimeMark", Value: req.OverTimeMark})
	}
	if req.CountDown > 0 {
		currentTime := time.Now().Unix() + int64(req.CountDown*3600) - 5*24*3600
		filter = append(filter, bson.E{Key: "paymentAt", Value: bson.M{"$lte": currentTime * 1000}})
		hasStatusFilter := false
		filterStatus := []uint{8, 9, 10}
		for _, e := range filter {
			if e.Key == "status" {
				hasStatusFilter = true
				if !util.Contains(filterStatus, uint(req.Status)) {
					filter = append(filter, bson.E{Key: "status", Value: 0})
				}
			}
		}
		if !hasStatusFilter {
			filter = append(filter, bson.E{Key: "status", Value: bson.M{"$in": filterStatus}})
		}
	}
	match := bson.D{{"$match", filter}}
	sort := bson.D{{"$sort", bson.M{"placedOrderAt": -1}}}
	unWind := bson.D{{"$unwind", "$skus"}}
	cursor, err := global.MongoDB.Collection("orders").Aggregate(context.TODO(), mongo.Pipeline{match, unWind, sort})
	if err != nil {
		return err
	}
	var orders []model.OrderExport
	if err = cursor.All(context.TODO(), &orders); err != nil {
		return err
	}
	//定义首行标题
	dataKey := make([]map[string]string, 0)
	dataKey = append(dataKey, map[string]string{
		"key":    "orderSn",
		"title":  "订单编号",
		"width":  "120",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "createdAt",
		"title":  "下单时间",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "paidAt",
		"title":  "支付时间",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "payType",
		"title":  "支付方式",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "status",
		"title":  "订单状态",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "skuId",
		"title":  "Fordeal SKU",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "skuNo",
		"title":  "商家SKU",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "overTime",
		"title":  "履约时效承诺",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "skuExtAttribute",
		"title":  "销售规格",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "originPrice",
		"title":  "单价",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "normalQuantity",
		"title":  "数量",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "finalPrice",
		"title":  "订单金额",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "deliverPlace",
		"title":  "发货地区",
		"width":  "50",
		"is_num": "0",
	})
	dataKey = append(dataKey, map[string]string{
		"key":    "saleCountry",
		"title":  "买家国家",
		"width":  "50",
		"is_num": "0",
	})
	fmt.Println(dataKey)
	//填充数据
	data := make([]map[string]interface{}, 0)
	status := map[int]string{
		3:  "已发货",
		5:  "交易成功",
		6:  "已拒签",
		7:  "已拒签",
		8:  "待补货",
		9:  "补货中",
		10: "处理中",
		99: "已取消",
	}
	if len(orders) > 0 {
		for _, v := range orders {
			data = append(data, map[string]interface{}{
				"orderSn":         v.OrderSn,
				"createdAt":       util.UnixToStr(int64(v.PlacedOrderAt/1000), "2006-01-02 15:04:05"),
				"paidAt":          util.UnixToStr(int64(v.PaymentAt/1000), "2006-01-02 15:04:05"),
				"payType":         v.PaymentType,
				"saleCountry":     v.SaleCountry,
				"deliverPlace":    v.DeliverPlace,
				"skuId":           v.Sku["skuId"],
				"skuNo":           v.Sku["skuNo"],
				"overTime":        v.Sku["overTime"],
				"status":          status[v.Status],
				"skuExtAttribute": v.Sku["skuExtAttribute"],
				"originPrice":     v.Sku["originPrice"],
				"normalQuantity":  v.Sku["normalQuantity"],
				"finalPrice":      v.Sku["finalPrice"],
			})
		}
	}
	util.NewMyExcel().ExportToWeb(dataKey, data, ctx)

	return nil
}
